package com.supplychain.scm.core.basis.util;

import com.google.common.collect.Lists;
import com.supplychain.scm.core.basis.annotation.EnumAlias;
import com.supplychain.scm.core.basis.annotation.Ignore;
import com.supplychain.scm.core.basis.enums.IBaseEnum;
import com.supplychain.scm.core.basis.enums.IEnum;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.configurationprocessor.json.JSONObject;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName EnumUtils
 * @Description 枚举工具类
 * @createTime 11:30:00 2023/12/22
 */
@UtilityClass
public class EnumUtils {

    public List<JSONObject> getEnumValues(String className, String label) {
        List<JSONObject> mappingList;
        try {
            Class<?> clazz = Class.forName(className);
            mappingList = getEnumValues(clazz, label);
        } catch (ClassNotFoundException e) {
            //log.warn("EnumUtils#getEnumValuesclassName:{} not found", className);
            mappingList = Lists.newArrayList();
        }
        return mappingList;
    }

    public List<JSONObject> getEnumValues(Class<?> enumClass, String label) {
        if (Objects.isNull(enumClass)) {
            return Collections.emptyList();
        }
        //Assert.isTrue(BaseEnum.class.isAssignableFrom(enumClass), "该枚举定义错误");
        //Assert.isTrue(enumClass.isEnum(), "该状态不属于枚举定义");
        Enum<?>[] enumConstants = (Enum<?>[]) enumClass.getEnumConstants();
        if (Objects.isNull(enumConstants)) {
            return Collections.emptyList();
        }
        Map<String, Field> fieldMap = Arrays.stream(enumClass.getFields()).collect(Collectors.toMap(Field::getName, field -> field));
        List<JSONObject> mappingList = Lists.newArrayList();
        for (Enum<?> enumConstant : enumConstants) {
            Field field = fieldMap.get(enumConstant.name());
            if (field.isAnnotationPresent(Deprecated.class) || (field.isAnnotationPresent(Ignore.class) && StringUtils.isBlank(label))) {
                continue;
            }
            if (StringUtils.isNotBlank(label) && field.isAnnotationPresent(Ignore.class)) {
                Ignore ignore = field.getAnnotation(Ignore.class);
                String[] excludeLabels = ignore.excludeLabels();
                if (!useLoop(excludeLabels, label)) {
                    continue;
                }
            }
            Class<?> declaringClass = enumConstant.getDeclaringClass();
            try {
                Object value = declaringClass.getMethod("getValue").invoke(enumConstant);
                Object desc;
                if(field.isAnnotationPresent(EnumAlias.class)) {
                    EnumAlias alias = field.getAnnotation(EnumAlias.class);
                    desc = alias.value();
                } else {
                    desc = declaringClass.getMethod("getDescribe").invoke(enumConstant);
                }
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("code", value);
                jsonObject.put("name", desc);
                mappingList.add(jsonObject);
            } catch (Exception e) {
                //log.warn("EnumUtils#getEnumValues error => {}", ExceptionUtils.getStackTrace(e));
            }
        }
        return mappingList;
    }

    /**
     * 枚举值对象比较
     */
    public <T extends Serializable> boolean eq(IEnum<T> enumObj, T val) {
        if (null == enumObj || null == val) {
            return false;
        }
        return enumObj.getValue().equals(val);
    }

    /**
     * 枚举值对象比较取反
     */
    public <T extends Serializable> boolean neq(IEnum<T> enumObj, T val) {
        return !eq(enumObj, val);
    }

    /**
     * 获取枚举对象值列表
     */
    public <E extends IEnum<T>, T extends Serializable> List<T> getValues(Class<E> enumClass) {
        if (Objects.isNull(enumClass)) {
            return Collections.emptyList();
        }
        E[] enumConstants = enumClass.getEnumConstants();
        if (Objects.isNull(enumConstants)) {
            return Collections.emptyList();
        }
        return Arrays.stream(enumConstants).map(IEnum::getValue).collect(Collectors.toList());
    }

    /**
     * 通过value获取枚举对象值描述
     */
    public <E extends IBaseEnum<?,V>,V extends Serializable> V getDescByCode(Class<E> enumClass, Object value) {
        E e = valueOf(enumClass, value);
        return Objects.isNull(e) ? null : e.getDescribe();
    }

    /**
     * 通过value获取枚举对象
     */
    public <E extends IBaseEnum<?,?>> E valueOf(Class<E> enumClass, Object value) {
        if (Objects.isNull(value)) {
            return null;
        }
        E[] enumConstants = enumClass.getEnumConstants();
        if (Objects.isNull(enumConstants)) {
            return null;
        }
        return Arrays.stream(enumConstants).filter(e -> Objects.equals(e.getValue(), value)).findFirst().orElse(null);
    }

    private boolean useLoop(String[] arr, String targetValue) {
        for (String s : arr) {
            if (s.equalsIgnoreCase(targetValue)) {
                return true;
            }
        }
        return false;
    }
}
